/*
 * socket.c
 *
 *  Created on: 2012-4-28
 *      Author: Administrator
 */


#include "../apue.h"
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h>

#define MAXSLEEP 128

int connect_retry (int sockfd, const struct sockaddr *addr, socklen_t alen) {
	int nsec;
	for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1)
	if (connect(sockfd, addr, alen)) {
		return 0;
	} else {
		if (nsec < MAXSLEEP/2) sleep(nsec);
	}
	return -1;
}


void print_family (const struct addrinfo *aip) {
	printf(" family ");
	switch (aip->ai_family) {
	case AF_INET:
		printf("inet");
		break;
	case AF_INET6:
		printf("inet6");
		break;
	case AF_UNIX:
		printf("unix");
		break;
	case AF_UNSPEC:
		printf("unspecified");
		break;
	default:
		printf("unkown (%d)", aip->ai_family);
		break;
	}
}

void print_type (const struct addrinfo *aip) {
	printf(" socket type ");
	switch (aip->ai_socktype) {
	case SOCK_DGRAM:
		printf("datagram");
		break;
	case SOCK_STREAM:
		printf("stream");
		break;
	case SOCK_SEQPACKET:
		printf("seqpacket");
		break;
	case SOCK_RAW:
		printf("raw");
		break;
	default:
		printf("unkown (%d)",aip->ai_socktype);
		break;
	}
}

void print_protocol (struct addrinfo *aip) {
	printf(" protocol ");
	switch (aip->ai_protocol) {
	case 0:
		printf("default");
		break;
	case IPPROTO_TCP:
		printf("tcp");
		break;
	case IPPROTO_UDP:
		printf("udp");
		break;
	case IPPROTO_RAW:
		printf("raw");
		break;
	default:
		printf("unknown (%d)", aip->ai_protocol);
		break;
	}
}

int initserver (const struct sockaddr* addr, socklen_t alen, int type, int protocol, int qlen) {
	int fd;
	int err = 0;

	if ((fd = socket(addr->sa_family, type, protocol)) < 0) {
		return fd;
	}

	if (bind(fd, addr, alen) < 0) {
		err = errno;
		goto errout;
	}

	if (type == SOCK_STREAM || SOCK_SEQPACKET) {
		if (listen(fd, qlen) < 0) {
			err = errno;
			goto errout;
		}
	}
	return fd;

errout:
	close(fd);
	errno = err;
	return -1;
}
